#pragma once

#include <iostream>
#include <string>
#include <cstring>
#include <strings.h>
#include <unistd.h>
#include <sys/socket.h>

#define SEP " "
#define SEP_LEN strlen(SEP)
#define LINE_SEP "\n\r"
#define LINE_SEP_LEN strlen(LINE_SEP)

enum{
    DIV_ZERO = 1,
    MOD_ZERO
};


class Request
{
public:
    Request()
    :_x(0),_y(0),_oper(0)
    {}
    Request(int x, int y, char op)
    :_x(x),_y(y),_oper(op)
    {}
    bool serialization(std::string* out)//序列化
    {
        //将一个请求结构转化成为对应的字节流
        //eg: 1 + 1
        //将x，y转换成相应的字符串
        std::string x_string = std::to_string(_x);
        std::string y_string = std::to_string(_y);
        if(x_string.empty() || y_string.empty()) return false;
        
        *out = "";
        *out += x_string;
        *out += SEP;
        *out += _oper;
        *out += SEP;
        *out += y_string;
        
        return true;
    }
    bool deserialization(const std::string& in)//反序列化
    {
        //将一个字节流转化成为一个结构化的请求
        //先找到第一个分隔符
        auto left = in.find(SEP);
        auto right = in.rfind(SEP);

        if(left == right || left == std::string::npos || right == std::string::npos) return false;

        std::string x_string = in.substr(0, left);
        std::string y_string = in.substr(right+SEP_LEN);

        if(x_string.empty() || y_string.empty()) return false;

        //此时下一个位置就是操作符
        _oper = in[left+SEP_LEN];
        
        _x = std::stoi(x_string);
        _y = std::stoi(y_string);

        return true;
    }
    ~Request()
    {}
public:
    int _x;
    int _y;
    char _oper;
};

class Response
{
public:
    Response()
    :_exitcode(0), _result(0)
    {}
    Response(int exitcode, int result)
    :_exitcode(exitcode), _result(result)
    {}
    bool serialization(std::string* out)//序列化
    {
        //将一个请求结构转化成为对应的字节流
        //eg: 0 1
        *out = "";
        *out += std::to_string(_exitcode);
        *out += SEP;
        *out += std::to_string(_result);
        return true;
    }
    bool deserialization(const std::string& in)//反序列化
    {
        //将一个字节流转化成为一个结构化的响应
        //eg: 0 1
        //先从最开始找到第一个分隔符
        int pos = in.find(SEP, 0);
        if(pos == std::string::npos) return false;
        std::string exitcode_string = in.substr(0, pos);
        //此时分隔符后面就都是结果了
        std::string result_string = in.substr(pos+SEP_LEN);
        //此时就得到了退出码和结果
        if(exitcode_string.empty() || result_string.empty()) return false;
        _exitcode = std::stoi(exitcode_string);
        _result = std::stoi(result_string);
        return true;
    }
    ~Response()
    {}
public:
    int _exitcode;
    int _result;
};


bool cal(const Request& req, Response* resp)
{
    resp->_exitcode = 0;
    resp->_result = 0;

    switch(req._oper)
    {
    case '+':
        resp->_exitcode = 0;
        resp->_result = req._x + req._y;
        break;
    case '-':
        resp->_exitcode = 0;
        resp->_result = req._x - req._y;
        break;
    case '*':
        resp->_exitcode = 0;
        resp->_result = req._x * req._y;
        break;
    case '/':
        {
            if(!req._y) 
            {
                resp->_exitcode = DIV_ZERO;
                resp->_result = 0;
            }
            else
            {
                resp->_exitcode = 0;
                resp->_result = req._x / req._y;
            }
        }
        break;
    case '%':
        {
            if(!req._y) 
            {
                resp->_exitcode = MOD_ZERO;
                resp->_result = 0;
            }
            else
            {
                resp->_exitcode = 0;
                resp->_result = req._x % req._y;
            }
        }
        break;
    default:
        return false;
    }
    return true;
}

const std::string enLength(const std::string& content)//增加报头
{
    //"content"    
    std::string send_msg = std::to_string(content.size());//得到有效载荷的长度
    send_msg += LINE_SEP;//为有效载荷增加行分隔符
    send_msg += content;
    send_msg += LINE_SEP;//将长度字符串加上行分隔符

    return send_msg;
}

bool deLength(const std::string& text, std::string *content)//去掉报头
{
    //"content_len"\n\r"content"\n\r
    auto pos = text.find(LINE_SEP);
    if(pos == std::string::npos) return false;
    std::string s_content_len = text.substr(0, pos);
    int content_len = std::stoi(s_content_len);
    *content = text.substr(pos+LINE_SEP_LEN, content_len);
    return true;
}

bool recvTxt(int sock, std::string* txt, std::string& inbuffer)
{
#define NUM 1024
    char line[NUM];
    *txt = "";
    while(true)
    {
        ssize_t n = read(sock, line, sizeof(line));
        if(n > 0)
        {
            inbuffer += line;//将line的内容直接追加到输入缓冲区中
            bzero(line, sizeof(line));//再将line的内容进行清空，防止出现重复的情况
            int pos = inbuffer.find(LINE_SEP, 0);
            if(pos == std::string::npos) continue;//说明此时连该有效载荷的长度都还没有
            std::string s_content_len = inbuffer.substr(0, pos);//获得有效载荷的长度
            int content_len = std::stoi(s_content_len);
            int all_len = s_content_len.size() + 2*LINE_SEP_LEN + content_len;
            if(inbuffer.size() < all_len) continue;//说明此时还没有获得一个完整的请求
            *txt = inbuffer.substr(0, all_len);//获得整个字节流
            inbuffer.erase(0, all_len);//将已经获得的字节流直接从输入缓冲区中删除
            break;
        }
        else return false;
    }
    return true;
}
